
#include <mtx_util.h>
#include <matrix.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>

char help = 0;
char comp_readable = 0;
char new_file = 0;
char *new_file_name;
char ops[5]; // 0=add;1=sub;2=mult;3=inv;4=det
int matrix_files_index = 7; // 8 is the default length
int matrix_files_len = 0;
char **matrix_files;

vm_matrix **matrices;
int num_matrices;

int parse_args(int, char**);
int parse_operations(char *);
int load_matrices();
void print_help_info();
void print_prog_info();
void print_matrices();

int main(int argc, char **argv){

  fprintf(stderr, "Parsing args: ");
  int ok = parse_args(argc, argv);
  if (ok){
    fprintf(stderr, "OK\n");
  } else {
    fprintf(stderr, "Error detected parsing args; exiting.\n");
    exit(1);
  }
  
  if (help){
    print_help_info();
  } else {
    print_prog_info();
  }

  /* Load the matrices here. */
  if (!load_matrices()){
    fprintf(stderr, "Unable to load matrices: exiting.\n");
    exit(1);
  }
  fprintf(stderr, "Using these matrices:\n");
  print_matrices();

  /* Now we are ready to run the operations. */
  int i = 0;
  for ( ; i < 5; i++){
    int result = 0;
    if (ops[i]){
      switch (i) {
      case OP_ADD:
	result = add_matrices(matrices, num_matrices);
	break;
      case OP_SUB:
	result = sub_matrices(matrices, num_matrices);
	break;
      case OP_MULT:
	result = mult_matrices(matrices, num_matrices);
	break;
      case OP_INV:
	result = inv_matrices(matrices, num_matrices);
	break;
      case OP_DET:
	result = det_matrices(matrices, num_matrices);
	break;
      }
      if (!result) printf("Error doing operation: %d\n", i);
    }
  }

}

void _extend_matrix_file_list(){

  

}

void print_help_info(){

  fprintf(stderr, "Help\n");

}

int parse_args(int argc, char **argv){

  // Start of with 8 possible file entries. Its likely to be enough.
  matrix_files = (char **)malloc(sizeof(char *) * 8);
  int cur_mtx_ind = 0;

  int i = 1;
  for ( ; i < argc; i++){
    if (argv[i][0] != '-'){
      return 0;
    } else if (argv[i][1] == 'f'){ // -f: a file name for a matrix
      if ((i+1) >= argc) {
	return 0;
      }
      if (matrix_files_index > cur_mtx_ind){
	matrix_files[cur_mtx_ind++] = argv[++i];
      } else {
	_extend_matrix_file_list();
	matrix_files[cur_mtx_ind++] = argv[++i];
      }
    } else if (argv[i][1] == 'r'){ // -r: result matrix is readable to a prog
      comp_readable = 1;
    } else if (argv[i][1] == 'n'){ // -n: write the new matrix into a new file
      if ((i+1) >= argc) {
	return 0;
      }
      new_file = 1;
      new_file_name = argv[++i];
    } else if (argv[i][1] == 'o'){ // -o: operation to do
      if (!(parse_operations(argv[++i]))){
	return 0;
      }
    } else if (argv[i][1] == 'h'){ // -h: help listing
      help = 1;
    }
  }
  matrix_files_len = cur_mtx_ind;
  return 1;
}

int parse_op_str(char *str){

  if (strcmp(str, "add") == 0){
    ops[0] = 1;
    return 1;
  } else if (strcmp(str, "sub") == 0){
    ops[1] = 1;
    return 1;
  } else if (strcmp(str, "mult") == 0){
    ops[2] = 1;
    return 1;
  } else if (strcmp(str, "inv") == 0){
    ops[3] = 1;
    return 1;
  } else if (strcmp(str, "det") == 0){
    ops[4] = 1;
    return 1;
  } else {
    fprintf(stderr, "Error found\n");
    return 0;
  }

}

int parse_operations(char *ops){

  fprintf(stderr, "Parsing operations...\n");
  char *cur_str = ops;
  int i = 0, len = strlen(ops);

  for ( ; i <= len; i++){
    if (ops[i] == ','){
      ops[i] = 0;
      if (!parse_op_str(cur_str)){
	return 0;
      }
      cur_str = ops + (++i);
    } else if (ops[i] == 0){
      if (!parse_op_str(cur_str)){
	return 0;
      }
      
    }
  }
  return 1;

}

void print_prog_info(){

  fprintf(stderr, "Matrix Files:\n");
  int i = 0;
  for ( ; i < matrix_files_len; i++){
    fprintf(stderr, "  file: %s\n", matrix_files[i]);
  }
  if (new_file){
    fprintf(stderr, "Writing output to file: %s\n", new_file_name);
  }


  fprintf(stderr, "Adding:      %s\n", ops[0] ? "Yes" : "No");
  fprintf(stderr, "Subtracting: %s\n", ops[1] ? "Yes" : "No");
  fprintf(stderr, "Multiplying: %s\n", ops[2] ? "Yes" : "No");
  fprintf(stderr, "Inversing:   %s\n", ops[3] ? "Yes" : "No");
  fprintf(stderr, "Determinant: %s\n", ops[4] ? "Yes" : "No");

}

int load_matrices(){

  if (matrix_files_len == 0) return 0;
  num_matrices = matrix_files_len - 1;

  matrices = (vm_matrix **)malloc(sizeof(vm_matrix *)*(matrix_files_len));
  if (matrices == NULL){
    perror("Matrices array is null");
    return 0;
  }

  int i = 0;
  for ( ; i < matrix_files_len; i++){
    matrices[i] = vm_read_matrix(matrix_files[i]);
    if (matrices[i] == NULL){
      return 0;
    }
  }

  return 1;

}

void print_matrices(){

  int i = 0;
  for ( ; i < matrix_files_len; i++){
    vm_fprint_matrix(stderr, matrices[i], "  ");
  }

}
